package com.tanhua.server.service;

import com.alibaba.fastjson.JSON;
import com.tanhua.commons.exception.TanHuaException;
import com.tanhua.commons.templates.FaceTemplate;
import com.tanhua.commons.templates.HuanXinTemplate;
import com.tanhua.commons.templates.OssTemplate;
import com.tanhua.commons.templates.SmsTemplate;
import com.tanhua.domain.db.User;
import com.tanhua.domain.db.UserInfo;
import com.tanhua.domain.vo.ErrorResult;
import com.tanhua.domain.vo.UserInfoVo;
import com.tanhua.dubbo.api.UserApi;
import com.tanhua.dubbo.api.UserInfoApi;
import com.tanhua.server.interceptor.UserHolder;
import com.tanhua.server.utils.GetAgeUtil;
import com.tanhua.server.utils.JwtUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.Reference;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * 消费层的service
 */
@Service
@Slf4j
public class UserService {

    //远程调用注入 UserApi
    @Reference
    private UserApi userApi;

    //远程调用 UserInfoApi
    @Reference
    private UserInfoApi userInfoApi;

    //注入短信模板对象（通用模块，不用远程调用）
    @Autowired
    private SmsTemplate smsTemplate;

    //注入配置文件中属性
    @Value("${tanhua.redisValidateCodeKeyPrefix}")
    private String redisValidateCodeKeyPrefix;

    //注入redis
    @Autowired
    private RedisTemplate redisTemplate;

    //注入JwtUtils工具类对象
    @Autowired
    private JwtUtils jwtUtils;

    //注入人脸检测 FaceTemplate对象
    @Autowired
    private FaceTemplate faceTemplate;

    //注入上传图片 OssTemplate对象
    @Autowired
    private OssTemplate ossTemplate;

    @Autowired
    private HuanXinTemplate huanXinTemplate;

    /**
     * 根据手机号查询用户
     *
     * @param mobile
     * @return
     */
    public ResponseEntity findByMobile(String mobile) {

        User user = userApi.findByMobile(mobile);

        return ResponseEntity.ok(user);
    }

    /**
     * 新增用户
     *
     * @return
     */
    public ResponseEntity saveUser(User user) {

        userApi.save(user);
        return ResponseEntity.ok(null);
    }

    /**
     * 登陆案例1-发送验证码
     *
     * @param phone
     */
    public void sendValidateCode(String phone) {
        //1.通过手机号来获取redis中的验证码
        String key = redisValidateCodeKeyPrefix + phone;
        String codeInRedis = (String) redisTemplate.opsForValue().get((key));
        //2.redis中有值，则报错:验证码没有过期
        if (codeInRedis != null) {
            throw new TanHuaException(ErrorResult.duplicate());
        }
        //TODO
        //3.redis中没有值，生成验证码
        //这是一个java自带的工具类 RandomStringUtils
        String validateCode = "123456";/*RandomStringUtils.randomNumeric(6);
        //4调用smsTemplate发送验证码
        Map<String, String> sendResult = smsTemplate.sendValidateCode(phone, validateCode);
        //5.发送验证码返回的信息不能为空
        if (sendResult != null) {
            throw new TanHuaException(ErrorResult.fail());
        }*/
        //用占位符看看日志里面是否成功，验证码 和 手机号 是否多少
        log.info("发送验证码成功。${},${}", validateCode, key);
        //5.存入redis中 有效期十分钟
        redisTemplate.opsForValue().set(key, validateCode, 10, TimeUnit.MINUTES);
    }

    /**
     * 登陆案例2-校验登录
     *
     * @param phone
     * @param verificationCode
     * @return
     */
    public Map<String, Object> loginVerification(String phone, String verificationCode) {
        //1.验证码校验
        //2.拼接验证码的key
        String key = redisValidateCodeKeyPrefix + phone;
        //3.从redis中获取验证码
        String codeInRedis = (String) redisTemplate.opsForValue().get(key);
        log.info("codeInRedis,verificationCode: {},{}", codeInRedis, verificationCode);
        //4.如果redis中没有则表示过期了，报错（需要让用户重新获取）
        if (codeInRedis == null) {
            throw new TanHuaException(ErrorResult.loginError());
        }
        //5.判断验证码是否一致
        if (!StringUtils.equals(codeInRedis, verificationCode)) {
            //5.1不一致：报错
            throw new TanHuaException(ErrorResult.validateCodeError());
        }
        //5.2一致：查询数据库判断用户手机号是否为第一次登录
        //5.2.1 删除redis中的key 防止重读提交
        redisTemplate.delete(key);
        User user = userApi.findByMobile(phone);
        //默认设置成是已经注册
        Boolean isNew = false;
        if (user == null) {
            //5.2.1是第一次登陆 则注册为新用户
            user = new User();
            user.setMobile(phone);
            //这里用用户的手机号后六位设置成密码 并使用加密方式为DigestUtils.md2Hex
            user.setPassword(DigestUtils.md2Hex(phone.substring(6)));
            //第一次登陆并没有id 需要先调用方法添加完成过后再返回id回来
            Long userId = userApi.save(user);
            user.setId(userId);
            //新注册
            isNew = true;

            // 注册环信上的账号
            huanXinTemplate.register(userId);

        }
        //6.0签发 token 会用到用户的id，和手机号码
        String token = jwtUtils.createJWT(phone, user.getId());
        //6.1以token为key ，以用户信息为value存入redis，并设置有效期为七天
        //6.2把user对象转换成json数据存入redis 并把token加上前缀
        String tokenKey = "TOKEN_" + token;
        String UserJsonString = JSON.toJSONString(user);
        redisTemplate.opsForValue().set(tokenKey, UserJsonString, 7, TimeUnit.DAYS);
        //7.构建返回信息 (返回map集合)
        Map<String, Object> result = new HashMap<>();
        result.put("token", token);
        result.put("isNew", isNew);
        //8.返回结果 result
        return result;
    }



    /**
     * 完善用户信息
     * @param userInfoVo

     */
    public void loginReginfo(UserInfoVo userInfoVo ) {

      /*
        不使用拦截器 获取token中的信息
        //验证token是否有效
        User loginUser = getUserByToken(token);
        Long loginUserId = loginUser.getId();

       */

        //获取登录用户的id--使用拦截器
        Long loginUserId = UserHolder.getUserId();
        //vo转成db的pojo
        UserInfo userInfo = new UserInfo();
        //复制属性把P1复制到P2去念书姓名及类型不许一直，如果不一致则不会复制
        BeanUtils.copyProperties(userInfoVo, userInfo);
        //把登陆用户的id设置进去
        userInfo.setId(loginUserId);
        //计算年龄
        userInfo.setAge(GetAgeUtil.getAge(userInfoVo.getBirthday()));
        //调用userapi添加用户信息
        userInfoApi.add(userInfo);


    }

    /**
     * 完善用户信息- 选取头像
     *
     * @param headPhoto
     */
    public void uploadAvatar(MultipartFile headPhoto) {

        // 通过token来获取登录用户的信息
        User loginUser = UserHolder.getUser();
        try {
            //人脸检测
            if (!faceTemplate.detect(headPhoto.getBytes())) {
                //没通过人脸检测抛出异常
                throw new TanHuaException(ErrorResult.faceError());
            }
            //上传到oss
            String url = ossTemplate.upload(headPhoto.getOriginalFilename(), headPhoto.getInputStream());
            //调用api来更新用户的头像
            UserInfo userInfo = new UserInfo();
            userInfo.setId(loginUser.getId());
            userInfo.setAvatar(url);
            userInfoApi.update(userInfo);
        } catch (IOException e) {
            throw new TanHuaException("上传头像失败");
        }

    }

    /**
     * 查看用户登录的信息
     * @return
     */
    public UserInfoVo getLoginUserInfo() {
        //获取用户id
        Long userId = UserHolder.getUserId();
        //调用api查询用户详情
        UserInfo userInfo = userInfoApi.findId(userId);
        //转成vo
        UserInfoVo userInfoVo = new UserInfoVo();
        BeanUtils.copyProperties(userInfo, userInfoVo);
        //返回 vo
        return userInfoVo;
    }

    /**
     * 更新用户信息
     * @param vo
     */
    public void updateUserInfo( UserInfoVo vo) {
        //获取登录用户id
        Long id = UserHolder.getUserId();
        //转成userinfo
        UserInfo userInfo = new UserInfo();
        BeanUtils.copyProperties(vo, userInfo);
        //计算年龄
        userInfo.setAge(GetAgeUtil.getAge(vo.getBirthday()));
        //设置id
        userInfo.setId(id);
        //调用api更新
        userInfoApi.update(userInfo);
    }

    /**
     * 更新用户头像
     * @param headPhoto
     */
    public void updateAvatar( MultipartFile headPhoto) {
        try {
            //通过token来获取登录用户的信息
            User loginUser = UserHolder.getUser();
            //2.上传到oss
            String url = ossTemplate.upload(headPhoto.getOriginalFilename(), headPhoto.getInputStream());
            // 人脸检测
            if (!faceTemplate.detect(headPhoto.getBytes())) {
                throw new TanHuaException(ErrorResult.faceError());
            }
            //调用api来更新用户的头像
            UserInfo userInfo = new UserInfo();
            userInfo.setId(loginUser.getId());
            userInfo.setAvatar(url);
            userInfoApi.update(userInfo);
        } catch (IOException e) {
            log.error("上传头像失败");
            throw new TanHuaException("上传头像失败");
        }
    }
}
